home *** CD-ROM | disk | FTP | other *** search
- /*
- ARAStatus.c
-
- Extension to show the connection status of ARA. Will add a system menu to control
- various functions of ARA. Also, show the connect time.
-
- by Patrick Beard & Chris Allen.
-
- © 1992 Gene Scott Software.
- */
-
- #include <string.h>
- #include <Traps.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <stddef.h>
-
- #ifndef __MENUS__
- #include <Menus.h>
- #endif
- #ifndef __GESTALTEQU__
- #include <GestaltEqu.h>
- #endif
- #ifndef __REMOTEACCESSINTERFACE__
- #include <RemoteAccessInterface.h>
- #endif
- #ifndef __NOTIFICATION__
- #include <Notification.h>
- #endif
-
- #include "Exceptions.h"
- #include "Extension.h"
- #include "GenericPatch.h"
- #include "IconSuite.h"
- #include "MenusList.h"
- #include "ShowIconFamily.h"
-
-
- static int dprintf(const char* format, ...);
-
- #if __option(a4_globals)
- #define cBaseSystemMenuId -16488
- #else
- #define cBaseSystemMenuId 5000
- #endif
-
- enum {
- eAboutARAStatus = 1,
- eDisconnect,
- eShowTimeConnected
- };
-
- enum {
- eNotConnectedIcon = 0,
- eConnectedIcon,
- eTransitionIcon
- };
-
- #define cAboutStrings 128
-
- struct IconString {
- char itsLength; // always 5.
- char itsFlag; // always 1.
- Handle itsSuite; // handle to an icon suite.
- };
-
- typedef struct IconString IconString;
-
- //
- // globals.
- //
-
- #pragma mark globals
-
- IconString theIconStrings[3];
- MenuHandle theARAStatusMenu;
- MenuHandle theTimeConnectedMenu;
- long theLastTimeConnected = 0;
- Boolean theShowTimeConnected = true;
- Boolean theConnectionState = false;
- Boolean theMenuBarDirty = false;
- unsigned char theEmptyStr[1] = { '\0' };
- Str255 theAboutMessage;
-
- //
- // ARA functions.
- //
-
- static void ARADisconnect()
- {
- TRemoteAccessParamBlock pb;
-
- // set up the Remote Access PB
- pb.DISCONNECT.csCode = RAM_EXTENDED_CALL; // extended call
- pb.DISCONNECT.resultStrPtr = nil; // don’t want result strings
- pb.DISCONNECT.extendedType = (Ptr)REMOTEACCESSNAME; // to Remote Access
- pb.DISCONNECT.extendedCode = CmdRemoteAccess_Disconnect; // disconnect command
- pb.DISCONNECT.portGlobalsPtr = nil; // user port
- pb.DISCONNECT.abortOnlyThisPB = nil; // don't get tied to any specific pb
- pb.DISCONNECT.optionFlags = 0| kNSShowStatus; // show status while disconnecting
- PBRemoteAccess(&pb, false); // issue sync call
- }
-
- static TRemoteAccessStatusParam* ARAStatus()
- {
- static TRemoteAccessParamBlock thePB;
- register TRemoteAccessParamBlock* pb = &thePB;
- static long sequence = 0;
-
- // set up the Status PB
- pb->STATUS.csCode = RAM_EXTENDED_CALL; // extended call
- pb->STATUS.resultStrPtr = nil; // put results here
- pb->STATUS.portGlobalsPtr = nil; // do UserPort
- pb->STATUS.extendedType = (Ptr)REMOTEACCESSNAME; // to Netshare
- pb->STATUS.extendedCode = CmdRemoteAccess_Status; // status command
- pb->STATUS.userNamePtr = nil;
- pb->STATUS.connectedToNamePtr = nil;
- pb->STATUS.theLastStatusMsgPtr = nil;
- pb->STATUS.statusUserNamePtr = nil;
- pb->STATUS.statusMsgSeqNum = sequence++; // set seqnum
-
- PBRemoteAccess(pb, false);
-
- return &pb->STATUS;
- }
-
- //
- // Nasty menu manipulation functions.
- //
-
- #pragma mark menu_functions
-
- static short StrWidth(StringPtr str)
- {
- GrafPtr* portPtr = *(GrafPtr**)GetA5();
- GrafPtr oldPort;
- short width;
-
- oldPort = *portPtr, *portPtr = WMgrPort;
- width = StringWidth(str);
- *portPtr = oldPort;
-
- return width;
- }
-
- static Boolean IdInMenuList(MenusListHandle menuList, short id)
- {
- MenusList* menus = *menuList;
- short i, menuCount = menus->itemsOffset / sizeof(MenuElement);
-
- for (i = 0; i < menuCount; ++i) {
- MenuHandle m = menus->elements[i].menu;
- if ((**m).menuID == id) return true;
- }
- return false;
- }
-
- static void DirectInsertMenu(MenusListHandle menuList, MenuHandle menu, MenuHandle before)
- {
- short id = cBaseSystemMenuId;
- MenuHandle leftMenu = nil;
- MenusList* menus;
- short i, menuCount;
- MenuElement newElement;
- long offset;
- short width;
-
- HLock(menuList);
- menus = *menuList;
- menuCount = menus->itemsOffset / sizeof(MenuElement);
-
- // compute width of the menu title.
- HLock(menu);
- width = 8 + StrWidth((**menu).menuData);
- HUnlock(menu);
-
- // generate a unique id.
- while (IdInMenuList(menuList, id)) ++id;
-
- (**menu).menuID = id;
- newElement.menu = menu;
- if (!before) {
- newElement.leftEdge = menus->rightEdge;
- menus->rightEdge = newElement.leftEdge + width;
- offset = sizeof(MenusList) + menus->itemsOffset; // menuCount * sizeof(MenuElement)
- } else {
- MenuElement* elements = menus->elements;
- for (i = 0; i < menuCount; ++i, ++elements) {
- if (elements->menu == before) {
- offset = sizeof(MenusList) + i * sizeof(MenuElement);
- newElement.leftEdge = elements->leftEdge - width - 4;
- break;
- }
- }
- }
- menus->itemsOffset += 6;
- HUnlock(menuList);
- Munger(menuList, offset, nil, 0, (Ptr)&newElement, sizeof(MenuElement));
- }
-
- static void DirectRemoveMenu(MenusListHandle menuList, MenuHandle menu)
- {
- MenusList* menus = *menuList;
- short i, menuCount = menus->itemsOffset / sizeof(MenuElement);
-
- // remove the menu from the list.
- for (i = 0; i < menuCount; ++i) {
- if (menus->elements[i].menu == menu) {
- MenuElement element;
- long offset = sizeof(MenusList) + i * sizeof(MenuElement);
- Munger(menuList, offset, nil, sizeof(MenuElement), (Ptr)&element, 0);
- menus->itemsOffset -= 6;
- break;
- }
- }
- }
-
- static void RemoveMenu(MenuHandle menu)
- {
- DeleteMenu((**menu).menuID);
- }
-
- static void SetMenuTitle(MenuHandle menu, StringPtr title)
- {
- // change the title.
- Munger(menu, offsetof(MenuInfo, menuData), nil, 1 + (**menu).menuData[0], title, 1 + title[0]);
- }
-
- static void RightJustify(MenusListHandle menuList, MenuHandle menu, StringPtr title, short adjust)
- {
- short width = adjust + StrWidth(title);
- // change the width! assume right justification.
- MenusList* menus = *menuList;
- short menuCount = menus->itemsOffset / sizeof(MenuElement);
- MenuElement* element = menus->elements;
- short i;
-
- for (i = 0; i < menuCount; ++i, ++element) {
- if (element->menu == menu) {
- element->leftEdge = (element + 1)->leftEdge - width;
- break;
- }
- }
- }
-
- //
- // InsertMenuPatch -- Add our menus to the menu list after the system does.
- //
-
- class InsertMenuPatch : public GenericPatch {
- public:
- InsertMenuPatch(void);
- virtual void Behavior(void);
- };
-
- struct InsertMenuParameters {
- short itsBefore;
- MenuHandle itsMenu;
- };
-
- typedef struct InsertMenuParameters InsertMenuParameters;
-
- typedef pascal void (*InsertMenuProc) (MenuHandle menu, short before);
-
- InsertMenuPatch::InsertMenuPatch()
- {
- GenericPatch::InitGenericPatch(_InsertMenu, sizeof(InsertMenuParameters));
- Install();
- }
-
- void InsertMenuPatch::Behavior()
- {
- InsertMenuProc oldInsertMenu = (InsertMenuProc)itsOld;
- InsertMenuParameters* params = (InsertMenuParameters*)itsFrame->parameters;
-
- // see if our menus are in the current menu bar.
- if (!IdInMenuList(theMenus, (**theARAStatusMenu).menuID)) {
- // if not, add our menus after the system does.
- (*oldInsertMenu)(theTimeConnectedMenu, 0);
- (*oldInsertMenu)(theARAStatusMenu, 0);
- #if __option(a4_globals)
- Disable();
- return;
- #endif
- }
-
- #if !__option(a4_globals)
- if (params->itsBefore == 0) {
- (*oldInsertMenu) (params->itsMenu, (**theTimeConnectedMenu).menuID);
- AbortTrap();
- }
- #endif
- }
-
- static void DoAbout(StringPtr aboutMessage)
- {
- static NMRec notification = { nil, nmType };
- notification.nmStr = aboutMessage;
- notification.nmResp = (ProcPtr)-1;
- NMInstall(¬ification);
- }
-
- //
- // MenuSelectPatch -- grab menu items after they are selected.
- //
-
- class MenuSelectPatch : public GenericPatch {
- public:
- MenuSelectPatch(void);
- virtual void Behavior(void);
- };
-
- struct MenuSelectParameters {
- Point itsStartPt;
- long itsResult;
- };
-
- typedef struct MenuSelectParameters MenuSelectParameters;
-
- typedef pascal long (*MenuSelectProcPtr) (Point pt);
-
- MenuSelectPatch::MenuSelectPatch()
- {
- GenericPatch::InitGenericPatch(_MenuSelect, offsetof(MenuSelectParameters, itsResult));
- Install();
- }
-
- void MenuSelectPatch::Behavior()
- {
- MenuSelectProcPtr oldMenuSelect = (MenuSelectProcPtr)itsOld;
- MenuSelectParameters* params = (MenuSelectParameters*)itsFrame->parameters;
- long result;
-
- DirectRemoveMenu(theMenus, theTimeConnectedMenu);
-
- #if !__option(a4_globals)
- { long oldA5 = SetA5((long)itsFrame->ra5);
- #endif
-
- params->itsResult = (*oldMenuSelect)(params->itsStartPt);
-
- #if !__option(a4_globals)
- SetA5(oldA5); }
- #endif
-
- DirectInsertMenu(theMenus, theTimeConnectedMenu, theARAStatusMenu);
-
- EnableItem(theTimeConnectedMenu, 0);
- AbortTrap();
- result = MenuDisable;
- if ((result >> 16) == (**theARAStatusMenu).menuID) {
- short item = result & 0xffff;
- params->itsResult = 0;
- switch (item) {
- case eAboutARAStatus:
- DoAbout(theAboutMessage);
- break;
- case eDisconnect:
- ARADisconnect();
- break;
- case eShowTimeConnected:
- theShowTimeConnected = !theShowTimeConnected;
- CheckItem(theARAStatusMenu, item, theShowTimeConnected);
- if (!theShowTimeConnected) {
- SetMenuTitle(theTimeConnectedMenu, theEmptyStr);
- RightJustify(theMenus, theTimeConnectedMenu, theEmptyStr, -4);
- theMenuBarDirty = true;
- theLastTimeConnected = 0;
- }
- break;
- }
- }
- }
-
- //
- // SystemTaskPatch - here we show the time connected periodically.
- //
-
- class SystemTaskPatch : public GenericPatch {
- public:
- SystemTaskPatch(void);
- virtual void Behavior(void);
- };
-
- SystemTaskPatch::SystemTaskPatch()
- {
- GenericPatch::InitGenericPatch(_SystemTask, 0);
- Install();
- }
-
- extern KeyMap theKeyMap : 0x174;
-
- void SystemTaskPatch::Behavior()
- {
- TRemoteAccessStatusParam* status = ARAStatus();
- Boolean connected = ((status->statusBits & CctlConnected) != 0);
- #if !__option(a4_globals)
- Boolean controlKeyDown = ((theKeyMap[1] & 8) != 0);
-
- if (controlKeyDown)
- status->timeConnected++;
- connected = (connected || controlKeyDown);
- #endif
-
- if (connected && theShowTimeConnected) {
- if (status->timeConnected != theLastTimeConnected) {
- char timeBuf[10];
- short hours, minutes, seconds;
-
- theLastTimeConnected = status->timeConnected;
- seconds = theLastTimeConnected;
- minutes = seconds / 60;
- hours = minutes / 60;
- minutes = minutes % 60;
- seconds = seconds % 60;
- sprintf(timeBuf, "%02d:%02d:%02d", hours, minutes, seconds);
- SetMenuTitle(theTimeConnectedMenu, c2pstr(timeBuf));
- RightJustify(theMenus, theTimeConnectedMenu, (StringPtr)timeBuf, 10);
- theMenuBarDirty = true;
- }
- }
-
- // see if we're now connected.
- if (connected != theConnectionState) {
- theConnectionState = connected;
- SetMenuTitle(theARAStatusMenu, (StringPtr)&theIconStrings[connected]);
- if (connected) {
- EnableItem(theARAStatusMenu, eDisconnect);
- } else {
- // clear the time connected value.
- DisableItem(theARAStatusMenu, eDisconnect);
- SetMenuTitle(theTimeConnectedMenu, theEmptyStr);
- RightJustify(theMenus, theTimeConnectedMenu, theEmptyStr, -4);
- }
- theMenuBarDirty = true;
- }
-
- if (theMenuBarDirty) {
- theMenuBarDirty = false;
- DrawMenuBar();
- }
- }
-
- static void DetachSuite(Handle suiteHandle)
- {
- int i;
- IconSuite* suite = *(IconSuite**)suiteHandle;
-
- for (i = 0; i < IconSpace; ++i) {
- Handle icon = suite->table[i];
- if (icon)
- DetachResource(icon);
- }
- }
-
- static void GetIconString(IconString* iconStr, short id)
- {
- OSErr result = GetIconSuite(&iconStr->itsSuite, id, -1L);
- FailNil(iconStr->itsSuite);
- FailErr(result);
- DetachSuite(iconStr->itsSuite);
- iconStr->itsLength = 5;
- iconStr->itsFlag = 1;
- }
-
- //
- // Install routine. This is where you allocate your patch objects.
- // Throw an exception if something fails.
- //
-
- void Install()
- {
- OSErr result;
- long flags;
- short i;
-
- try {
- // make sure ARA is around.
- result = Gestalt(gestaltRemoteAccessAttr, &flags);
- FailErr(result);
- FailAssert(flags & (1 << gestaltRemoteAccessExists));
-
- // enough of ARA exists to satisfy us. install patches....
-
- // initialize enough for the menu manager.
- InitFonts();
-
- // allocate our icon suites.
- for (i = 0; i < 3; ++i)
- GetIconString(&theIconStrings[i], 1000 + i);
-
- // get the about string.
- GetIndString(theAboutMessage, cAboutStrings, 1);
-
- // create our system menus.
- theTimeConnectedMenu = NewMenu(cBaseSystemMenuId + 1, theEmptyStr);
- FailNil(theTimeConnectedMenu);
- (**theTimeConnectedMenu).menuWidth = 0;
-
- theARAStatusMenu = NewMenu(cBaseSystemMenuId, theEmptyStr);
- FailNil(theARAStatusMenu);
- AppendMenu(theARAStatusMenu, "\pAbout ARA Status;(Disconnect;Show Time Connected!");
-
- // stuff in the not connected icon.
- SetMenuTitle(theARAStatusMenu, (StringPtr)&theIconStrings[eNotConnectedIcon]);
-
- // patch MenuSelect to check for selections in our menu.
- new MenuSelectPatch;
-
- // patch InsertMenu to add our menus when an app does.
- new InsertMenuPatch;
-
- // patch SystemTask to update time connected display.
- new SystemTaskPatch;
-
- ShowIconFamily(128);
- } catch {
- // extension failed, show sad icon.
- ShowIconFamily(129);
- throw(theException);
- }
- }
-
- //
- // Remove routine. This is called when system is shutdown, or an exception
- // is thrown.
- //
-
- void Remove()
- {
- Patch::RemoveAll();
- RemoveMenu(theARAStatusMenu);
- DisposeMenu(theARAStatusMenu);
- RemoveMenu(theTimeConnectedMenu);
- DisposeMenu(theTimeConnectedMenu);
- }
-
- //
- // debugging printf.
- //
-
- static int dprintf(const char* format, ...)
- {
- va_list args;
- static char str[256];
- int count;
-
- va_start(args, format);
- count = vsprintf(str, format, args);
- va_end(args);
- DebugStr(c2pstr(str));
-
- return count;
- }
-